home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d21
/
pc_ipc.arc
/
IPCSAMP.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-12-03
|
9KB
|
275 lines
page 60,132
;PROGRAM : IPCSAMP.ASM
; This program demonstrates the use of IPC in Assembly. It is
; self-contained in that it makes no references to external data
; or procedures. This sample was tested with Microsoft MACRO
; Assembler, version 1.27, and Borland Turbo Link, version 1.1,
; as follows:
; masm ipcsamp.asm, ipcsamp.obj, ipcsamp.lst, ipcsamp.crf
; tlink /m /s /n /d /c ipcsamp.obj,ipcsamp.exe,ipcsamp.map
; ipcsamp [data]
;
; IPCSAMP initially determines whether IPC is installed by two steps.
; First, if IPC's default interrupt vector (60h) is 0000:0000, IPC is
; not installed. Second, a call is made to the interrupt routine and
; the value returned in param.status is checked. If status is not
; INSTALLED and ENABLED, IPC is not installed.
;
; IPCSAMP next checks the command line for data to be passed to IPC.
; If no data is present, a default string is used.
;
; The data is sent to IPC and the return status checked. If no errors
; occured, the data is retrieved and displayed on the standard output.
;
;EQUATES
S_ID EQU 0 ; sending process id
R_ID EQU 0 ; receiving process id
CMND_INQ EQU 1 ; IPC_CMND_INQUIRE
CMND_RDATA EQU 6 ; IPC_CMND_RDATA
CMND_SDATA EQU 7 ; IPC_CMND_SDATA
IPC_VECTOR EQU 60h ; use default IPC vector
ERROR_FLAG EQU 8 ; mask for return status
INST_ENAB EQU 6 ; installed, enabled flags
ERR_NOTINST EQU 12 ; IPC_ERR_NOTINST
CMND_LEN_OFF EQU 080h ; offset of command length
CMND_OFF EQU 081h ; offset of command
CMND_LEN_MAX EQU 07Fh ; max command length
IRET_INST EQU 0CFh ; iret instruction
DOS_PRINT EQU 9 ; DOS print function
TERM_PROC EQU 04Ch ; DOS terminate process function
DOS_CALL EQU 021h ; DOS interrupt
GET_VECT EQU 035h ; DOS get interrupt vector
dataseg segment ;define data segment
IPC_PARAM_BLOCK struc ;define IPC_PARAM_BLOCK structure
my_id DW ?
to_id DW ?
command DW ?
status DW ?
error DW ?
data_size DW ?
data_ptr DD ?
IPC_PARAM_BLOCK ends
param IPC_PARAM_BLOCK <0,0,0,0,0,0,0> ; var of type IPC_PARAM_BLOCK
;declare a data buffer of 128 bytes
buf_struct struc
string DB CMND_LEN_MAX+1 dup (0)
buf_struct ends
buffer buf_struct <>
; declare a string of default data
my_data DB "Toto, I don't think we're in Kansas anymore!", 13
str_length DW 45 ; string length
; error messages and codes
badcmnd_str DB '001: Invalid command.$'
inst0_str DB '002: Only process 0 can install / reset PC-IPC.$'
cantenab_str DB '003: Only the disabling process can re-enable.$'
notenab_str DB '004: IPC is currently disabled.$'
cantdisab_str DB '005: This process cannot disable IPC.$'
badtoid_str DB '006: The to-process id is not valid.$'
badfmid_str DB '007: The from-process id is not valid.$'
noaddr_str DB '008: Invalid target address for data.$'
maxids_str DB '009: All available process ids are in use.$'
cantreli_str DB '010: That process id cannot be relinquished.$'
nomem_str DB '011: Insufficient memory available for message.$'
notinst_str DB '012: IPC is not installed. Run IPCINST.COM.$'
badcmnd DW offset badcmnd_str
inst0 DW offset inst0_str
cantenab DW offset cantenab_str
notenab DW offset notenab_str
cantdisab DW offset cantdisab_str
badtoid DW offset badtoid_str
badfmid DW offset badfmid_str
noaddr DW offset noaddr_str
maxids DW offset maxids_str
cantreli DW offset cantreli_str
nomem DW offset nomem_str
notinst DW offset notinst_str
dataseg ends
stakseg segment stack ; define stack segment
DB 20 dup ('stack ')
stakseg ends
progseg segment ; define code segment
s_data_asm proc far ; declare as a far proc
assume cs:progseg, ds:dataseg
start: ; starting execution address
; set up stack for return to DOS
push ds ; save old data segment
sub ax,ax ; put 0 in AX
push ax ; save it on stack
push ds ; save the PSP segment
; set up data segment
mov ax, dataseg
mov ds, ax
; verify that IPC is installed
mov ah, GET_VECT ; get the vector,
mov al, IPC_VECTOR ; returned in ES:BX
int dos_call
mov ax, es
cmp ax, 0 ; if vector is 0000:0000
jne inquire_ipc ; IPC is not installed
cmp bx, 0
jne inquire_ipc
pop ds ; (to balance stack)
mov ax, ERR_NOTINST ; print error msg and exit
jmp err_print
inquire_ipc:
mov param.command, CMND_INQ ; init command to inquire
mov param.status, 0 ; clear status field
; call IPC, equivalent to pc_ipc(vector, param_ptr)
push ds
mov ax, offset param.my_id
push ax
int IPC_VECTOR ; call IPC
add sp, 4 ; clean up stack
; check return status
mov ax, param.status ; check that IPC is
cmp ax, INST_ENAB ; installed, enabled
jz get_params
pop ds ; (to balance stack)
mov ax, ERR_NOTINST ; print error msg and exit
jmp err_print
; get a copy of the data (if any) from the DOS command line
; The command line parameters are located in the Program Segment Prefix
; at offset 081h (CMND_OFF). The length of the parameters is at offset
; 080h (CMND_LEN_OFF). When loaded as an .exe file, the PSP segment is
; automatically put in DS and ES by the loader.
get_params:
pop ds ; retore PSP segment
mov bx, CMND_LEN_OFF ; get cmnd line length
xor cx, cx ; clear CX
mov cl, byte ptr [ds:bx]
push ds ; save PSP segment
mov ax, dataseg
mov es, ax ; set up destination segment
mov ds, ax ; set up source segment
mov ax, offset buffer
mov di, ax ; set up destination offset
mov ax, offset my_data
mov si, ax ; set up source offset
cmp cx, 0 ; if length=0, use default data
jne get_cmnd_line
; use default data
pop ax ; discard PSP segment
mov cx, str_length ; set up string length
jmp move_data
get_cmnd_line: ; use command line data
mov str_length, cx ; save length for later
pop ds ; set up source segment
mov ax, CMND_OFF ; set up source offset
mov si, ax
move_data:
cld ; copy DS:SI --> ES:DI
rep movsb ; for CX bytes
xor al, al ; null terminate the string
dec di
mov byte ptr [es:di], al
; initialize the parameter block, equivalent to init_param_block(...)
init_param:
mov ax, dataseg ; set DS to dataseg segment
mov ds, ax
mov param.my_id, S_ID ; init my_id
mov param.to_id, R_ID ; init to_id
mov param.command, CMND_SDATA ; init command to send data
mov ax, str_length
mov param.data_size, ax ; init data_size
mov bx, offset param.my_id ; use BX to index param
mov word ptr [bx+12], offset buffer ; init data_ptr offset
mov word ptr [bx+14], ds ; init data_ptr segment
; send data to IPC
push ds
mov ax, offset param.my_id
push ax
int IPC_VECTOR
add sp, 4 ; clean up stack
; check for success
mov ax, param.error
mov bx, param.status
and bx, ERROR_FLAG
jnz err_print
; now get the data back from IPC
; initialize parameter block
mov param.my_id, S_ID ; init my_id
mov param.command, CMND_RDATA ; init command to read data
mov param.status, 0 ; clear status
mov bx, offset param.my_id ; use BX to index param
mov word ptr [bx+12], offset buffer ; init data_ptr offset
mov word ptr [bx+14], ds ; init data_ptr segment
; get the data
push ds
mov ax, offset param.my_id
push ax
int IPC_VECTOR
add sp, 4 ; clean up stack
; check for success
mov ax, param.error
mov bx, param.status
and bx, ERROR_FLAG
jnz err_print
; display data returned from IPC
mov bx, offset buffer
mov ax, param.data_size
add bx, ax
mov ax, '$' ; $ terminated string
mov [bx], ax
mov ah, DOS_PRINT ; display string function
mov dx, offset buffer ; display string at DS:DX
int DOS_CALL
mov ax, param.error ; return error in ERRORLEVEL
; return to DOS
done:
mov ah, TERM_PROC ; DOS terminate process func
int DOS_CALL ; al already has return code
err_print:
push ax ; save error number
mov bx, offset badcmnd ; get first msg ptr address
dec ax ; use cx to get msg address
jz incr_ptr_done
mov cx, ax ; find correct message ptr
incr_ptr:
add bx, 2 ; get next pointer's addr
loop incr_ptr ; loop until done
incr_ptr_done:
mov ax, dataseg
mov ds, ax
mov dx, word ptr [ds:bx] ; get msg pointer
print:
mov ah, DOS_PRINT ; display the error msg
int DOS_CALL
pop ax ; return error in ERRORLEVEL
jmp done
s_data_asm endp ; end of module
progseg ends ; end of code segment
end start ; end of assembly